#include "media/capturerenderadapter.h"

#include "base/logging.h"
#include "media/videocapturer.h"
#include "media/videoprocessor.h"
#include "media/videorenderer.h"

namespace cricket {

	CaptureRenderAdapter::CaptureRenderAdapter(VideoCapturer* video_capturer)
		: video_capturer_(video_capturer) {
	}

	CaptureRenderAdapter::~CaptureRenderAdapter() {
		// Have to disconnect here since |video_capturer_| lives on past the
		// destruction of this object.
		if (video_capturer_) {
			video_capturer_->SignalVideoFrame.disconnect(this);
		}
	}

	CaptureRenderAdapter* CaptureRenderAdapter::Create(
		VideoCapturer* video_capturer) {
			if (!video_capturer) {
				return NULL;
			}
			CaptureRenderAdapter* return_value = new CaptureRenderAdapter(video_capturer);
			return_value->Init();  // Can't fail.
			return return_value;
	}

	bool CaptureRenderAdapter::AddRenderer(VideoRenderer* video_renderer) {
		if (!video_renderer) {
			return false;
		}
		base::CritScope cs(&capture_crit_);
		if (IsRendererRegistered(*video_renderer)) {
			return false;
		}
		video_renderers_.push_back(VideoRendererInfo(video_renderer));
		return true;
	}

	bool CaptureRenderAdapter::RemoveRenderer(VideoRenderer* video_renderer) {
		if (!video_renderer) {
			return false;
		}
		base::CritScope cs(&capture_crit_);
		for (VideoRenderers::iterator iter = video_renderers_.begin();
			iter != video_renderers_.end(); ++iter) {
				if (video_renderer == iter->renderer) {
					video_renderers_.erase(iter);
					return true;
				}
		}
		return false;
	}

	void CaptureRenderAdapter::Init() {
		video_capturer_->SignalVideoFrame.connect(
			this,
			&CaptureRenderAdapter::OnVideoFrame);
	}

	void CaptureRenderAdapter::OnVideoFrame(VideoCapturer* capturer,
		const VideoFrame* video_frame) {
			base::CritScope cs(&capture_crit_);
			if (video_renderers_.empty()) {
				return;
			}
			MaybeSetRenderingSize(video_frame);

			for (VideoRenderers::iterator iter = video_renderers_.begin();
				iter != video_renderers_.end(); ++iter) {
					VideoRenderer* video_renderer = iter->renderer;
					video_renderer->RenderFrame(video_frame);
			}
	}

	// The renderer_crit_ lock needs to be taken when calling this function.
	void CaptureRenderAdapter::MaybeSetRenderingSize(const VideoFrame* frame) {
		for (VideoRenderers::iterator iter = video_renderers_.begin();
			iter != video_renderers_.end(); ++iter) {
				const bool new_resolution = iter->render_width != frame->GetWidth() ||
					iter->render_height != frame->GetHeight();
				if (new_resolution) {
					if (iter->renderer->SetSize(frame->GetWidth(), frame->GetHeight(), 0)) {
						iter->render_width = frame->GetWidth();
						iter->render_height = frame->GetHeight();
					} else {
						LOG(LS_ERROR) << "Captured frame size not supported by renderer: " <<
							frame->GetWidth() << " x " << frame->GetHeight();
					}
				}
		}
	}

	// The renderer_crit_ lock needs to be taken when calling this function.
	bool CaptureRenderAdapter::IsRendererRegistered(
		const VideoRenderer& video_renderer) const {
			for (VideoRenderers::const_iterator iter = video_renderers_.begin();
				iter != video_renderers_.end(); ++iter) {
					if (&video_renderer == iter->renderer) {
						return true;
					}
			}
			return false;
	}

}  // namespace cricket
